using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;
using JGSY.CMS.LowCode.Platform.Infrastructure.CmsDbContext;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Repositories
{
    /// <summary>
    /// 通用仓储基类实现
    /// 提供标准的CRUD操作和查询功能的基础实现，遵循Repository模式
    /// 所有具体实体的仓储类可以继承此类获得标准的数据访问功能
    /// 使用Entity Framework Core作为ORM框架进行数据持久化
    /// </summary>
    /// <typeparam name="T">实体类型，必须是引用类型</typeparam>
    public class Repository<T> : IRepository<T> where T : class
    {
        /// <summary>
        /// 数据库上下文实例
        /// </summary>
        protected readonly LowCodeDbContext _context;
        
        /// <summary>
        /// 当前实体类型的数据库表集合
        /// </summary>
        protected readonly DbSet<T> _dbSet;

        /// <summary>
        /// 初始化仓储实例
        /// </summary>
        /// <param name="context">数据库上下文</param>
        /// <exception cref="ArgumentNullException">当context为null时抛出</exception>
        public Repository(LowCodeDbContext context)
        {
            _context = context ?? throw new ArgumentNullException(nameof(context));
            _dbSet = context.Set<T>();
        }

        /// <summary>
        /// 根据ID异步获取实体
        /// </summary>
        /// <param name="id">实体标识符</param>
        /// <returns>匹配的实体，如果不存在则返回null</returns>
        /// <exception cref="ArgumentNullException">当id为null时抛出</exception>
        /// <exception cref="InvalidOperationException">当数据库操作失败时抛出</exception>
        public virtual async Task<T?> GetByIdAsync(object id)
        {
            return await _dbSet.FindAsync(id);
        }

        /// <summary>
        /// 异步获取所有实体
        /// 注意：此方法会加载表中所有数据，在大数据量情况下应谨慎使用
        /// </summary>
        /// <returns>所有实体的列表</returns>
        /// <exception cref="InvalidOperationException">当数据库操作失败时抛出</exception>
        public virtual async Task<List<T>> GetAllAsync()
        {
            return await _dbSet.ToListAsync();
        }

        /// <summary>
        /// 根据条件异步查找实体列表
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>匹配条件的实体列表</returns>
        /// <exception cref="ArgumentNullException">当predicate为null时抛出</exception>
        /// <exception cref="InvalidOperationException">当数据库操作失败时抛出</exception>
        public virtual async Task<List<T>> FindAsync(Expression<Func<T, bool>> predicate)
        {
            return await _dbSet.Where(predicate).ToListAsync();
        }

        /// <summary>
        /// 根据条件异步查找单个实体
        /// </summary>
        /// <param name="predicate">查询条件表达式</param>
        /// <returns>第一个匹配条件的实体，如果不存在则返回null</returns>
        /// <exception cref="ArgumentNullException">当predicate为null时抛出</exception>
        /// <exception cref="InvalidOperationException">当数据库操作失败时抛出</exception>
        public virtual async Task<T?> FindSingleAsync(Expression<Func<T, bool>> predicate)
        {
            return await _dbSet.FirstOrDefaultAsync(predicate);
        }

        /// <summary>
        /// 异步添加实体
        /// 注意：此方法仅将实体添加到上下文，需要调用SaveChanges才能持久化到数据库
        /// </summary>
        /// <param name="entity">要添加的实体</param>
        /// <returns>已添加的实体（可能包含生成的ID）</returns>
        /// <exception cref="ArgumentNullException">当entity为null时抛出</exception>
        /// <exception cref="InvalidOperationException">当数据库操作失败时抛出</exception>
        public virtual async Task<T> AddAsync(T entity)
        {
            await _dbSet.AddAsync(entity);
            return entity;
        }

        public virtual async Task<T> UpdateAsync(T entity)
        {
            _dbSet.Update(entity);
            return await Task.FromResult(entity);
        }

        public virtual async Task DeleteAsync(T entity)
        {
            _dbSet.Remove(entity);
            await Task.CompletedTask;
        }

        public virtual async Task DeleteAsync(object id)
        {
            var entity = await GetByIdAsync(id);
            if (entity != null)
            {
                await DeleteAsync(entity);
            }
        }

        public virtual async Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate)
        {
            return await _dbSet.AnyAsync(predicate);
        }

        public virtual async Task<int> CountAsync()
        {
            return await _dbSet.CountAsync();
        }

        public virtual async Task<int> CountAsync(Expression<Func<T, bool>> predicate)
        {
            return await _dbSet.CountAsync(predicate);
        }

        public virtual async Task<(List<T> Items, int Total)> GetPagedAsync(int pageIndex, int pageSize, Expression<Func<T, bool>>? predicate = null)
        {
            var query = _dbSet.AsQueryable();
            
            if (predicate != null)
            {
                query = query.Where(predicate);
            }

            var total = await query.CountAsync();
            var items = await query
                .Skip(pageIndex * pageSize)
                .Take(pageSize)
                .ToListAsync();

            return (items, total);
        }

        public virtual async Task<int> SaveChangesAsync()
        {
            return await _context.SaveChangesAsync();
        }
    }
}
